﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace DSAL
{
    public class LisenceFile
    {
        public static string SERIALNUMBER = "#SERIALNUMBER";

        /// <summary>
        /// 生成lisence文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="encryptionKey"></param>
        /// <param name="serialNumber"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static bool Save(string filePath, string encryptionKey, string serialNumber, Dictionary<string,string> content)
        {
            try
            {
                Dictionary<string, string> kv = new Dictionary<string, string>();
                foreach (string key in content.Keys)
                {
                    kv.Add(key, content[key]);
                }

                kv.Add(SERIALNUMBER, serialNumber);

                string docContent = BuildXDoc(kv);
                byte[] encryptData = Encryption.Encrypt(docContent, encryptionKey);
                FileInfo file = new FileInfo(filePath);
                if(file.Directory.Exists == false)
                {
                    file.Directory.Create();
                }
                File.WriteAllBytes(filePath, encryptData);
                return true;
            }
            catch (Exception ex)
            {
                if (File.Exists(filePath))
                {
                    try
                    {
                        File.Delete(filePath);
                    }
                    catch(Exception ex2)
                    {

                    }
                }
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="encryptionKey"></param>
        /// <param name="serialNumber">从lisence文件中返回的序列号</param>
        /// <returns></returns>
        public static Dictionary<string, string> Load(string filePath, string encryptionKey, out string serialNumber)
        {
            serialNumber = null;
            try
            {
                byte[] encryptData = File.ReadAllBytes(filePath);
                string docContent = Encryption.Decrypt(encryptData, encryptionKey);
                Dictionary<string, string> kv =  LoadXDoc(docContent);
                serialNumber = kv[SERIALNUMBER];
                kv.Remove(SERIALNUMBER);
                return kv;
            }
            catch(Exception ex)
            {
                return null;
            }
        }

        private static string BuildXDoc(Dictionary<string, string> kv)
        {
            using (Stream stream = new MemoryStream())
            {
                XDocument xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
                XElement xRoot = new XElement("props");
                xDoc.Add(xRoot);
                foreach (string key in kv.Keys)
                {
                    string value = kv[key];
                    XElement xItem = new XElement("item");
                    xItem.Add(new XAttribute("key", key));
                    xItem.Add(new XAttribute("value", value));
                    xRoot.Add(xItem);
                }
                xDoc.Save(stream);
                stream.Seek(0, SeekOrigin.Begin);
                using (StreamReader reader = new StreamReader(stream))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        private static Dictionary<string, string> LoadXDoc(string content)
        {
            Dictionary<string, string> kv = new Dictionary<string, string>();
            XDocument xDoc = XDocument.Parse(content);
            List<XElement> xKVList = xDoc.Element("props").Elements("item").ToList();
            for (int index = 0; index < xKVList.Count; index++)
            {
                string key = xKVList[index].Attribute("key").Value;
                string value = xKVList[index].Attribute("value").Value;

                kv.Add(key, value);
            }
            return kv;
        }

        public static bool SaveToSystemDir(string company, string product, string encryptionKey, string serialNumber, Dictionary<string, string> content)
        {
            string rawText = string.Format("{0}-{1}", company, product);
            string md5 = Encryption.convertToMd5(rawText);
            string path = string.Format("{0}\\{1}.dat", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), md5);
            return Save(path, encryptionKey, serialNumber, content);
        }

        public static Dictionary<string, string> LoadFromSystemDir(string company, string product, string encryptionKey, out string serialNumber)
        {
            try
            {
                string rawText = string.Format("{0}-{1}", company, product);
                string md5 = Encryption.convertToMd5(rawText);
                string path = string.Format("{0}\\{1}.dat", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), md5);
                return Load(path, encryptionKey, out serialNumber);
            }
            catch (Exception ex)
            {
                serialNumber = null;
                return null;
            }
        }
    }
}
